package com.example.kotlinTest

import java.math.BigDecimal

///////////////////////////////////
///////基础
///////////////////////////////////

//函数
fun sum(a: Int, b: Int): Int {
    return a + b
}

//将表达式作为函数体、 返回值类型自动推断的函数：
fun sum(a: Int, b: Int, c: Int) = a + b + c

//函数返回无意义的值：Unit可省略
fun printSum(a: Int, b: Int): Unit {
    println("sum of $a and $b is $(a+b)")
}

//字符串模板
fun charTemplate() {
    var a = 1
// 模板中的简单名称：
    val s1 = "a is $a"
    a = 2
// 模板中的任意表达式：
    val s2 = "${s1.replace("is", "was")}, but now is $a"
    println(s2)
}

//条件表达式
//fun maxOf(a:Int,b:Int):Int{
//    if(a>b){
//        return a
//    }else{
//        return b
//    }
//}
fun maxOf(a: Int, b: Int) = if (a > b) a else b

//**空值与null检测
/*
当某个变量的值可以为 null 的时候， 必须在声明处的类型后添加 ? 来标识该引用可为空。
如果 str 的内容不是数字返回 null ：
 */
fun parseInt(string: String): Int? {
    return string.toIntOrNull()
}

fun printProduct(arg1: String, arg2: String) {
    val x = parseInt(arg1)
    val y = parseInt(arg2)
    //////////////////////////////////////////////////////
// 直接使用 `x * y` 会导致编译错误， 因为它们可能为 null
    if (x != null && y != null) {
// 在空检测后， x 与 y 会自动转换为非空值（ non-nullable）
        println(x * y)
    } else {
        println("'$arg1' or '$arg2' is not a number")
    }
    //////////////////////////////////////////////////////
    if (x == null) {
        println("Wrong number format in arg1: '$arg1'")
        return
    }
    if (y == null) {
        println("Wrong number format in arg2: '$arg2'")
        return
    }
    /*
    在空检测后， x 与 y 会自动转换为非空值
     */
    println(x * y)
}

/*
类型检测与自动类型转换
is 运算符检测一个表达式是否某类型的一个实例。 如果一个不可变的局部变量或属性已经
判断出为某类型， 那么检测后的分支中可以直接当作该类型使用， 无需显式转换：
 */
fun getStringLength(obj: Any): Int? {
    if (obj is String) {
// `obj` 在该条件分支内自动转换成 `String`
        return obj.length
    }
    // 在离开类型检测分支后， `obj` 仍然是 `Any` 类型
    return null

//    if (obj !is String) return null
//// `obj` 在这一分支自动转换为 `String`
//    return obj.length
}

//for 循环
fun forTest() {
    val items = listOf("apple", "banana", "kiwifruit")

    for (item in items) {
        println(item)
    }

    for (index in items.indices) {
        println("item at $index is ${items[index]}")
    }
}

//while 循环
fun whileTest() {
    val items = listOf("apple", "banana", "kiwifruit")
    var index = 0
    while (index < items.size) {
        println("item at $index is ${items[index]}")
        index++
    }
}

//when表达式
fun describe(obj: Any): String =
    when (obj) {
        1 -> "One"
        "Hello" -> "Greeting"
        is Long -> "Long"
        !is String -> "Not a string"
        else -> "Unknown"
    }

//使用区间（ range）
fun rangeTest() {
    val x = 10
    val y = 9
    if (x in 1..y + 1) {
        println("fits in range")
    }

    //检测某个数字是否在指定区间外
    val list = listOf("a", "b", "c")
    if (-1 !in 0..list.lastIndex) {
        println("-1 is out of range")
    }
    if (list.size !in list.indices) {
        println("list size is out of valid list indices range, too")
    }

    //区间迭代
    for (z in 1..5) {
        print(z)
    }

    //数列迭代：
    for (z in 1..10 step 2) {
        print(z)
    }
    println()
    for (z in 9 downTo 0 step 3) {
        print(z)
    }
}

//集合
fun collectionTest() {
    //对集合进行迭代:
    val items = listOf("apple", "banana", "kiwifruit")
//sampleStart
    for (item in items) {
        println(item)
    }
//sampleEnd

    //使用 in 运算符来判断集合内是否包含某实例：
    val itemsSet = setOf("apple", "banana", "kiwifruit")
//sampleStart
    when {
        "orange" in itemsSet -> println("juicy")
        "apple" in itemsSet -> println("apple is fine too")
    }
//sampleEnd

    //使用 lambda 表达式来过滤（ filter） 与映射（ map） 集合：
    //sampleStart
    val fruits = listOf("banana", "avocado", "apple", "kiwifruit")
    fruits
        .filter { it.startsWith("a") }
        .sortedBy { it }
        .map { it.toUpperCase() }
        .forEach { println(it) }
//sampleEnd
}

//创建基本类及其实例
fun classTest() {
    //sampleStart
    val rectangle = Rectangle(5.0, 2.0)
    val triangle = Triangle(3.0, 4.0, 5.0)
//sampleEnd
    println("Area of rectangle is ${rectangle.calculateArea()}, its perimeter is ${rectangle.perimeter}")
    println("Area of triangle is ${triangle.calculateArea()}, its perimeter is ${triangle.perimeter}")
}

abstract class Shape(val sides: List<Double>) {
    val perimeter: Double get() = sides.sum()
    abstract fun calculateArea(): Double
}

interface RectangleProperties {
    val isSquare: Boolean
}

class Rectangle(
    var height: Double,
    var length: Double
) : Shape(listOf(height, length, height, length)), RectangleProperties {
    override val isSquare: Boolean get() = length == height
    override fun calculateArea(): Double = height * length
}

class Triangle(
    var sideA: Double,
    var sideB: Double,
    var sideC: Double
) : Shape(listOf(sideA, sideB, sideC)) {
    override fun calculateArea(): Double {
        val s = perimeter / 2
        return Math.sqrt(s * (s - sideA) * (s - sideB) * (s - sideC))
    }
}

/*
习惯用法
一些在 Kotlin 中广泛使用的语法习惯， 如果你有更喜欢的语法习惯或者风格， 建一个 pull request 贡献给我们吧！
 */
//创建DTOs（POJOs/POCOs）
/*
会为 Customer 类提供以下功能：
所有属性的 getters （ 对于 var 定义的还有 setters）
equals()
hashCode()
toString()
copy()
所有属性的 component1() 、 component2() ……等
 */
data class Customer(val name: String, val email: String)

//函数的默认参数
fun foo(a: Int = 0, b: String = "") {}
//过滤 list
//val positives = list.filter { x -> x > 0 }
//或者可以更短:
//val positives = list.filter { it > 0 }

//检测元素是否存在于集合中
//if ("john@example.com" in emailsList) {}
//if ("jane@example.com" !in emailsList) {}

//字符串内插 println("Name $name")

//类型判断
//when (x) {
//    is Foo //-> ……
//    is Bar //-> ……
//    else //-> ……
//}

//遍历 map/pair型list
//for ((k, v) in map) {
//    println("$k -> $v")
//}
//k 、 v 可以改成任意名字。

//使用区间
//for (i in 1..100) { …… } // 闭区间： 包含 100
//for (i in 1 until 100) { …… } // 半开区间： 不包含 100
//for (x in 2..10 step 2) { …… }
//for (x in 10 downTo 1) { …… }
//if (x in 1..10) { …… }

//只读map  访问list
val list = listOf("a", "b", "c")
val map = mapOf("a" to 1, "b" to 2, "c" to 3)

//访问 map
//println(map["key"])
//map["key"] = value

//延迟属性
//val p: String by lazy {
//// 计算该字符串
//}

//扩展函数
//fun String.spaceToCamelCase() { …… }
//"Convert this to camelcase".spaceToCamelCase()

//创建单例
object Resource {
    val name = "Name"
}

//Instantiate an abstract class 实例化一个抽象类
abstract class MyAbstractClass {
    abstract fun doSomething()
    abstract fun sleep()
}

fun testInstantiate() {
    val myObject = object : MyAbstractClass() {
        override fun doSomething() {
// ...
        }

        override fun sleep() { // ...
        }
    }
    myObject.doSomething()
}

//If not null 缩写
//val files = File("Test").listFiles()
//println(files?.size)

//If not null and else 缩写
//val files = File("Test").listFiles()
//println(files?.size ?: "empty")

//if null 执行一个语句
//val values = ……
//val email = values["email"] ?: throw IllegalStateException("Email is missing!")

//在可能会空的集合中取第一元素
//val emails = …… // 可能会是空集合
//val mainEmail = emails.firstOrNull() ?: ""

//if not null 执行代码
//val value = ……
//value?.let {
//    …… // 代码会执行到此处, 假如data不为null
//}

//映射可空值（ 如果非空的话）
//val value = ……
//val mapped = value?.let { transformValue(it) } ?: defaultValue
//// 如果该值或其转换结果为空， 那么返回 defaultValue。

//返回 when 表达式
fun transform(color: String): Int {
    return when (color) {
//        习惯用法
        "Red" -> 0
        "Green" -> 1
        "Blue" -> 2
        else -> throw IllegalArgumentException("Invalid color param value")
    }
}

//“try/catch”表达式
fun test() {
    val result = try {
//        count()
    } catch (e: ArithmeticException) {
        throw IllegalStateException(e)
    }
// 使用 result
}

//“if”表达式
fun foo(param: Int) {
    val result = if (param == 1) {
        "one"
    } else if (param == 2) {
        "two"
    } else {
        "three"
    }
}

//返回类型为 Unit 的方法的 Builder 风格用法
fun arrayOfMinusOnes(size: Int): IntArray {
    return IntArray(size).apply { fill(-1) }
}

//单表达式函数
//fun theAnswer() = 42
//等价于
//fun theAnswer(): Int {
//    return 42
//}
//单表达式函数与其它惯用法一起使用能简化代码， 例如和 when 表达式一起使用：
fun transform1(color: String): Int = when (color) {
    "Red" -> 0
    "Green" -> 1
    "Blue" -> 2
    else -> throw IllegalArgumentException("Invalid color param value")
}

//对 一个对象实例调用多个方法 （ with ）
class Turtle {
    fun penDown() {}
    fun penUp() {}
    fun turn(degrees: Double) {}
    fun forward(pixels: Double) {}
}
fun testWith(){
    val myTurtle = Turtle()
    with(myTurtle) { // 画一个 100 像素的正方形
        penDown()
        for (i in 1..4) {
            forward(100.0)
            turn(90.0)
        }
        penUp()
    }
}
//配置对象的属性（ apply ） 这对于配置未出现在对象构造函数中的属性非常有用。
//val myRectangle = Rectangle().apply {
//    length = 4
//    breadth = 5
//    color = 0xFAFAFA
//}

//Java 7 的 try with resources
//val stream = Files.newInputStream(Paths.get("/some/file.txt"))
//stream.buffered().reader().use { reader ->
//    println(reader.readText())
//}

//对于需要泛型信息的泛型函数的适宜形式
// public final class Gson {
// ……
// public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
    // ……
//inline fun <reified T : Any> Gson.fromJson(json: JsonElement): T = this.fromJson(
//    json, T::class.java
//)

//使用可空布尔
//val b: Boolean? = ……
//if (b == true) {
//    ……
//} else {
//// `b` 是 false 或者 null
//}

//交换两个变量
/*
also函数的结构实际上和let很像唯一的区别就是返回值的不一样，let是以闭包的形式返回，返回函数体内最后一行的值，
如果最后一行为空就返回一个Unit类型的默认值。
而also函数返回的则是传入对象的本身
#link https://blog.csdn.net/u013064109/article/details/78786646
Kotlin系列之let、with、run、apply、also函数的使用

 */
//var a = 1
//var b = 2
//a = b.also { b = a }

/*
TODO()： 将代码标记为不完整
Kotlin 的标准库有一个 TODO() 函数， 该函数总是抛出一个 NotImplementedError 。
其返回类型为 Nothing ， 因此无论预期类型是什么都可以使用它。 还有一个接受原因参数的重载：
IntelliJ IDEA的 kotlin 插件理解 TODO() 的语言， 并且会自动在 TODO 工具窗口中添加代码指示。
 */
fun calcTaxes(): BigDecimal = TODO("Waiting for feedback from accounting")

















//程序入口
fun main(args: Array<String>) {
    println("Hello World!")

    print("sum of 3 and 5 is ")
    println(sum(3, 5))

    printSum(-1, 0)

    println("max of 0 and 42 is ${maxOf(0, 42)}")

    //函数中定义函数
    fun printLength(obj: Any) {
        println("'$obj' string length is ${getStringLength(obj) ?: "... err, not a string"} ")
    }
    printLength("Incomprehensibilities")
    printLength(1000)
    printLength(listOf(Any()))

    println(describe(1))
    println(describe("Hello"))
    println(describe(1000L))
    println(describe(2))
    println(describe("other"))

    val text = """
    |Tell me and I forget.
    |Teach me and I remember.
    |Involve me and I learn.
    |(Benjamin Franklin)
    """
    val textTrimMargin = text.trimMargin()
    println(text)
    println(textTrimMargin)
}

/*
变量
类型自动推到
val 只能赋值一次  必须初始化
var 可多次赋值
 */


class Learn {

}